import os
import cv2
import numpy as np
import time


# 使用的Python库及对应版本：
# python 3.6
# opencv-python 3.3.0
# numpy 1.13.3
# 用到了opencv库中的模板匹配和边缘检测功能


def get_screenshot(id):
    print("getScreenShot");
    os.system('adb shell screencap -p /sdcard/%s.png' % str(id))

    print("pullScreenShot");
    os.system('adb pull /sdcard/%s.png .' % str(id))

def jump(distance):
    # 这个参数还需要针对屏幕分辨率进行优化
    press_time = int(distance * 1.35)
    cmd = 'adb shell input swipe 320 1500 320 1500 ' + str(press_time)
    os.system(cmd)


def get_center(img_canny, ):
    # 利用边缘检测的结果寻找物块的上沿和下沿
    # 进而计算物块的中心点
    # [max(row) for row in img_canny[400:]]这句代码表示输出img_canny图片的第400行到最后一行，每一行的最大值作为新的一维数组
    # np.nonzero(...)这个函数筛选出上面输出的每行最大值一维数组中所有非0的行数作为新的一维数组，np.nonzero(...)[0][0]选出一维数组的第一个值也就是要跳的方块的最上的顶点
    # 加上400是一开始从第400行开始检索，过滤掉上面的分数的干扰
    y_top = np.nonzero([max(row) for row in img_canny[400:]])[0][0] + 400
    x_top = int(np.mean(np.nonzero(img_canny[y_top])))

    # img_canny[y_top+5:][x_top]这段代码将img_canny第x_top列中从y_top+5行到最后一行的值抽出作为新的数组
    # np.nonzero(...)选取出这个数组的非0元素的下标，也就是img_canny的第x_top列的所有的边界点(除了第一个点，上顶点)
    y_bottom = np.nonzero(img_canny[y_top+10:,x_top])[0][0]+y_top+10

    #有些线和背景颜色混在一起了导致边缘检测没有检测出这种线


    # 对于不能很好的边缘检测的方块（便利店，木纹椅子这些）直接加上一个值为bottom
    if (y_bottom-y_top)<20:
        y_bottom=y_top+40

    x_center, y_center = x_top, (y_top + y_bottom) // 2
    return img_canny, x_center, y_center


# 第一次跳跃的距离是固定的
jump(530)
time.sleep(1)

# 匹配小跳棋的模板
temp1 = cv2.imread('temp_player.jpg', 0)
w1, h1 = temp1.shape[::-1]
# 匹配游戏结束画面的模板
temp_end = cv2.imread('temp_end.jpg', 0)
# 匹配中心小圆点的模板
temp_white_circle = cv2.imread('temp_white_circle.jpg', 0)
w2, h2 = temp_white_circle.shape[::-1]

# 循环直到游戏失败结束
for i in range(10000):
    sys_time=time.time()
    get_screenshot(0)
    img_gray = cv2.imread('%s.png' % 0, 0)  # %表示占位符（也就是读取0.png）,第二个参数0表示以灰度模式读取图片

    # 如果在游戏截图中匹配到带"再玩一局"字样的模板，则循环中止
    res_end = cv2.matchTemplate(img_gray, temp_end, cv2.TM_CCOEFF_NORMED)
    if cv2.minMaxLoc(res_end)[1] > 0.95:
        print('Game over!')
        break

    # 模板匹配截图中小跳棋的位置
    # max_val1表示最匹配的值，越接近1越匹配；max_loc1表示最匹配的位置的左上角顶点的坐标
    res1 = cv2.matchTemplate(img_gray, temp1, cv2.TM_CCOEFF_NORMED)
    min_val1, max_val1, min_loc1, max_loc1 = cv2.minMaxLoc(res1)
    center1_loc = (max_loc1[0] + w1//2, max_loc1[1] + h1-20)

    # 先尝试匹配截图中的中心原点，
    # 如果匹配值没有达到0.95，则使用边缘检测匹配物块上沿
    res2 = cv2.matchTemplate(img_gray, temp_white_circle, cv2.TM_CCOEFF_NORMED)
    min_val2, max_val2, min_loc2, max_loc2 = cv2.minMaxLoc(res2)
    if max_val2 > 0.95:
        print('found white circle!')
        x_center, y_center = max_loc2[0] + w2 // 2, max_loc2[1] + h2 // 2
    else:
        # 先做高斯模糊能提高边缘检测的效果
        img_gray = cv2.GaussianBlur(img_gray, (3, 3), 0)
        cv2.imwrite("gray_%f.png" % 0, img_gray)
        # 边缘检测
        canny_img = cv2.Canny(img_gray, 1, 20)
        H, W = canny_img.shape

        # 消去小跳棋轮廓对边缘检测结果的干扰
        for k in range(max_loc1[1] - 10, max_loc1[1] + 100):
            for b in range(max_loc1[0] - 10, max_loc1[0] + 100):
                canny_img[k][b] = 0

        canny_img, x_center, y_center = get_center(canny_img)

    # 标记出识别出来的两个中心点
    cv2.circle(canny_img, (x_center, y_center), 10, 255, -1)
    cv2.circle(canny_img, (center1_loc[0], center1_loc[1]), 10, 255, -1)

    # 将图片输出以供调试
    cv2.imwrite("canny_%f.png" % 0, canny_img)

    distance = (center1_loc[0] - x_center) ** 2 + (center1_loc[1] - y_center) ** 2
    distance = distance ** 0.5
    jump(distance)
    time.sleep(1.5)
